package com.mybatis.util;

import com.mvc.dao.IUserDao;
import com.mybatis.sqlSession.SqlSession;

import java.lang.reflect.*;
import java.util.List;

/**
 * @Description mybatis如何实现基于jdk接口实现动态代理。。。。。
 * @Author xsd
 * @Date 2020/6/13 7:53
 * JDK代理，代理的是接口，那么 既然代理的是接口，那如果没有实现类怎么办，能不能代理。答案是可以的，Mybatis就是这样的
 *
 * 	Mybatis使用JDK动态代理来实现Mapper接口，事先保存好Mapper接口，和接口声明的方法，返回值，参数类型
 * 	然后代理类的方法调用的时候使用MapperMethod这个事先放入方法缓存里的对象来真实调用功能
 *
 */
public class SubjectProxy2<T> implements InvocationHandler {

    private Class<T> proxyInterface;
    //这里可以维护一个缓存，存这个接口的方法抽象的对象
    private SqlSession sqlSession;


    public SubjectProxy2(Class<T> proxyInterface,SqlSession sqlSession){
        this.proxyInterface = proxyInterface;
        this.sqlSession=sqlSession;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        String className = method.getDeclaringClass().getName();
        String statementId = className+"."+methodName;
        // 准备参数2：params:args
        // 获取被调用方法的返回值类型
        Type genericReturnType = method.getGenericReturnType();
        // 获取被调用方法的返回值类型值
        String typeName = genericReturnType.getTypeName();
        // 判断是否进行了 泛型类型参数化
        if(genericReturnType instanceof ParameterizedType){
            List<Object> objects = sqlSession.selectList(statementId, args);
            return objects;
        }else if(typeName.equalsIgnoreCase("int")){
            return sqlSession.update(statementId, args);
        }
        return sqlSession.selectOne(statementId,args);
    }

    public T getProxy(){
        return (T) Proxy.newProxyInstance(proxyInterface.getClassLoader(),new Class[]{proxyInterface},this);
    }

    public static void main(String[] args) throws Exception {
        SubjectProxy2<IUserDao> subjectProxy2 = new SubjectProxy2(IUserDao.class,null);
        IUserDao subject2 = subjectProxy2.getProxy();
        subject2.findAll();
    }
}